﻿using System;
using System.Collections.Generic;
using System.Text;

namespace MandelbrotLib
{
    public class RealNumber : IComparable<RealNumber>, IEquatable<RealNumber>
    {
        protected const UInt32 kMaxU32 = 0xffffffff;
        protected const UInt32 kMaxU16 = 0xffff;
        protected const UInt32 kMaxU16P1 = 0x10000;
        protected const int kDefaultDecp = 1;

        protected enum Sign : sbyte
        {
            Negative = -1,
            Zero = 0,
            Positive = 1
        }

        protected Sign mSign = Sign.Zero;
        protected UInt32[] mChunks = new UInt32[0];  /* from least significant to most */
        protected int mEffeciveLength = 0;  /**
                                             * effective chunk length, 
                                             * the length in terms of the number 
                                             * of 32-bit chunks measured from the
                                             * beginning of the chunk sequence to
                                             * the last chunk which contains non-
                                             * zero value.
                                             * it may not always be the effective
                                             * length in the mathematical sense, 
                                             * the exceptional case happens
                                             * when there are trailing zeros involved
                                             * in the numerical sequence, which appear 
                                             * at the beginning of the chunk sequence.
                                             * to remove this anormaly, the object
                                             * needs to be renormed
                                             */
        protected int mDecimalPointPos = 0; /* the position of decimal point 
                                             * aligned to 32-bit boundaries
                                             * might be negative
                                             */

        protected static RealNumber kZero = new RealNumber();

        public int EffictiveChunkLength
        {
            get
            {
                return mEffeciveLength;
            }
        }

        public int ChunksAfterDecimalPoint
        {
            get
            {
                return Math.Max(mDecimalPointPos, 0);
            }
        }


        public static RealNumber Zero
        {
            get
            {
                return kZero;
            }
        }

        public bool IsZero
        {
            get
            {
                return mSign == Sign.Zero;
            }
        }

        public RealNumber()
        {
        }

        public void Renorm()
        {
            int highest;
            int lowest;
            for (highest = this.mEffeciveLength - 1; highest >= 0; highest--)
            {
                if (this.mChunks[highest] != 0)
                {
                    break;
                }
            }
            for (lowest = 0; lowest < highest; lowest++)
            {
                if (this.mChunks[highest] != 0)
                {
                    break;
                }
            }

            this.mEffeciveLength = highest - lowest + 1;
            this.mDecimalPointPos -= lowest;

            // decimal point position doesn't change
            UInt32[] chunks = new UInt32[this.mEffeciveLength];
            if (this.mEffeciveLength > 0)
            {
                Array.Copy(this.mChunks, lowest, chunks, 0, this.mEffeciveLength);
            }
            else
            {
                this.mSign = Sign.Zero;
            }
            this.mChunks = chunks;
        }

        public static RealNumber CreateByNumerator(int num)
        {
            if (num == 0)
            {
                return Zero;
            }

            RealNumber result = new RealNumber();

            result.mChunks = new UInt32[1] { (UInt32)Math.Abs(num) };
            result.mEffeciveLength = 1;
            result.mDecimalPointPos = 0;

            result.mSign = num > 0 ? Sign.Positive : Sign.Negative;

            return result;
        }

        public static RealNumber CreateByDenominator(int denom)
        {
            return CreateByDenominator(denom, kDefaultDecp);
        }

        /*
         * 'decp' is the number of chunks allowed after the decimal point
         */
        public static RealNumber CreateByDenominator(int denom, int decp)
        {
            int i;
            int ecl = 0;
            UInt32 a, b;
            UInt32 sum_a = 0;
            UInt32 den = (UInt32)Math.Abs(denom);
            UInt32 powOf16 = 16;
            UInt32 u  = 0;

            bool nonzero = false;
            bool reached = false;

            int leadingZeroChunks = 0;
            int digitPos = 0;

            List<UInt32> chunks = new List<uint>();

            int max_i = decp * 8;
            for (i = 0; i < max_i && !reached; i++)
            {
                b = powOf16 - sum_a * den;
                reached = ((b % den) == 0);
                a = b / den;
                sum_a = (sum_a + a) * 16;
                powOf16 *= 16;

                if (a > 0)
                {
                    nonzero = true;
                }

                if (nonzero)
                {
                    digitPos = i % 8;
                    digitPos = 7 - digitPos;
                    a <<= (digitPos * 4);
                    u |= a;

                    if ((i % 8) == 7)
                    {
                        chunks.Insert(0, u);
                        ecl = chunks.Count;
                        u = 0;
                    }
                }
                else if ((i % 8) == 7)
                {
                    leadingZeroChunks++;
                }
            }

            if (u != 0)
            {
                chunks.Insert(0, u);
                ecl = chunks.Count;
            }

            RealNumber result = new RealNumber();

            result.mChunks = new UInt32[chunks.Count];
            chunks.CopyTo(result.mChunks);

            result.mSign = denom > 0 ? Sign.Positive : Sign.Negative;
            result.mEffeciveLength = ecl;
            result.mDecimalPointPos = ecl + leadingZeroChunks;

            return result;
        }


        public int CompareTo(RealNumber that)
        {
            if (this.mSign == that.mSign)
            {
                int cr = 0;
                if (this.mSign == Sign.Zero)
                {
                    return 0;
                }

                cr = AbsCompareTo(that);

                if (this.mSign == Sign.Negative)
                {
                    cr = -cr;
                }

                return cr;
            }
            else
            {
                if (this.mSign == Sign.Positive)
                {
                    return 1;
                }
                else if (this.mSign == Sign.Negative)
                {
                    return -1;
                }
                else if (that.mSign == Sign.Positive)
                {   /* this is zero */
                    return -1;
                }
                else
                {   /* this is zero, that is negative */
                    return 1;
                }
            }
        }

        public int AbsCompareTo(RealNumber that)
        {
            return Compare(this.mChunks, that.mChunks, 
                this.mDecimalPointPos, that.mDecimalPointPos,
                this.mEffeciveLength, that.mEffeciveLength);
        }

        public RealNumber Copy()
        {
            if (this.mSign == Sign.Zero)
            {
                return Zero;
            }

            RealNumber copy = new RealNumber();
            copy.mChunks = new UInt32[this.mEffeciveLength];
            Array.Copy(this.mChunks, copy.mChunks, this.mEffeciveLength);
            copy.mSign = this.mSign;
            copy.mEffeciveLength = this.mEffeciveLength;
            copy.mDecimalPointPos = this.mDecimalPointPos;
            return copy;
        }

        public RealNumber GetNegative()
        {
            if (this.mSign == Sign.Zero)
            {
                return Zero;
            }
            RealNumber copy = new RealNumber();
            if (this.mSign == Sign.Positive)
            {
                copy.mSign = Sign.Negative;
            }
            else /*this.mSign == Sign.Negative*/
            {
                copy.mSign = Sign.Positive;
            }

            copy.mChunks = new UInt32[this.mEffeciveLength];
            Array.Copy(this.mChunks, copy.mChunks, this.mEffeciveLength);
            copy.mEffeciveLength = this.mEffeciveLength;
            return copy;
        }

        public void TurnNegative()
        {
            if (this.mSign == Sign.Positive)
            {
                this.mSign = Sign.Negative;
            }
            else if (this.mSign == Sign.Negative)
            {
                this.mSign = Sign.Positive;
            }
        }

        /*
         * 'decp' is the new positive decimal point position
         * which is the number of chunks after the decimal point
         */
        public void RoundTo(int decp)
        {
            if (this.mDecimalPointPos <= decp || decp <= 0)
            {   // nothing to be rounded
                return;
            }

            int d = this.mDecimalPointPos - decp;
            int newecl = this.mEffeciveLength - d;
            int i, j;

            if (newecl < 0)
            {   // to round too much
                return;
            }

            UInt32[] newChunks = new UInt32[newecl];

            for (i = d, j = 0; i < this.mEffeciveLength; i++, j++)
            {
                newChunks[j] = this.mChunks[i];
            }

            this.mChunks = newChunks;
            this.mDecimalPointPos = decp;
            this.mEffeciveLength = newecl;

            if (this.mEffeciveLength == 0)
            {
                this.mSign = Sign.Zero;
            }
        }

        /*
         * it is zero-renorm-free
         * which means the result will never be 
         * a number with zero value (zero in effective length)
         * but without a zero sign to signify that
         */
        public RealNumber Add(RealNumber that)
        {
            if (this.mSign == Sign.Zero)
            {
                return that.Copy();
            }
            else if (that.mSign == Sign.Zero)
            {
                return this.Copy();
            }

            RealNumber result = new RealNumber();
            if (this.mSign == that.mSign)
            {
                Add(out result.mChunks, out result.mDecimalPointPos,
                    out result.mEffeciveLength, 
                    this.mChunks, that.mChunks,
                    this.mDecimalPointPos, that.mDecimalPointPos,
                    this.mEffeciveLength, that.mEffeciveLength);
                result.mSign = this.mSign;
            }
            else
            {   
                int cr = this.AbsCompareTo(that);
                if (cr > 0)
                {   /* this is dominant */
                    Sub(out result.mChunks,
                        out result.mDecimalPointPos, 
                        out result.mEffeciveLength,
                        this.mChunks, that.mChunks, 
                        this.mDecimalPointPos, that.mDecimalPointPos,
                        this.mEffeciveLength, that.mEffeciveLength);
                    result.mSign = this.mSign;
                }
                else if (cr < 0)
                {   /* that is dominant */
                    Sub(out result.mChunks,
                        out result.mDecimalPointPos,
                        out result.mEffeciveLength,
                        that.mChunks, this.mChunks,
                        that.mDecimalPointPos, this.mDecimalPointPos, 
                        that.mEffeciveLength, this.mEffeciveLength);
                    result.mSign = that.mSign;
                }
                else
                {
                    return Zero;
                }
            }
            
            if (result.mEffeciveLength == 0)
            {
                return Zero;
            }

            return result;
        }

         /*
          * it is zero-renorm-free
          */
        public RealNumber Sub(RealNumber that)
        {
            if (this.mSign == Sign.Zero)
            {
                return that.GetNegative();
            }
            if (that.mSign == Sign.Zero)
            {
                return this.Copy();
            }

            RealNumber result = new RealNumber();

            if (this.mSign != that.mSign)
            {
                Add(out result.mChunks, out result.mDecimalPointPos,
                    out result.mEffeciveLength,
                    this.mChunks, that.mChunks,
                    this.mDecimalPointPos, that.mDecimalPointPos,
                    this.mEffeciveLength, that.mEffeciveLength);
                result.mSign = this.mSign;
            }
            else
            {
                int cr = this.AbsCompareTo(that);
                if (cr > 0)
                {   /* this is dominant */
                    Sub(out result.mChunks, out result.mDecimalPointPos,
                        out result.mEffeciveLength, 
                        this.mChunks, that.mChunks,
                        this.mDecimalPointPos, that.mDecimalPointPos, 
                        this.mEffeciveLength, that.mEffeciveLength);
                    result.mSign = this.mSign;
                }
                else if (cr < 0)
                {   /* that is dominant */
                    Sub(out result.mChunks, out result.mDecimalPointPos,
                        out result.mEffeciveLength, 
                        that.mChunks, this.mChunks,
                        that.mDecimalPointPos, this.mDecimalPointPos, 
                        that.mEffeciveLength, this.mEffeciveLength);
                    result.mSign = that.mSign == Sign.Positive? 
                        Sign.Negative : Sign.Positive;
                }
                else
                {
                    return Zero;
                }
            }

            if (result.mEffeciveLength == 0)
            {
                return Zero;
            }

            return result;
        }

         /*
          * it is zero-renorm-free
          */
        public RealNumber Mul(RealNumber that)
        {
            RealNumber result = new RealNumber();

            if (this.mSign == Sign.Zero || that.mSign == Sign.Zero)
            {
                return Zero;
            }

            result.mSign = this.mSign == that.mSign ? Sign.Positive : Sign.Negative;
            result.mDecimalPointPos = this.mDecimalPointPos + that.mDecimalPointPos;
            result.mEffeciveLength = Mul(out result.mChunks, 
                this.mChunks, that.mChunks,
                this.mEffeciveLength, that.mEffeciveLength);

            return result;
        }

        public RealNumber Add(int that)
        {
            return this.Add(CreateByNumerator(that));
        }

        public RealNumber Sub(int that)
        {
            return this.Sub(CreateByNumerator(that));
        }

        public RealNumber Mul(int that)
        {
            RealNumber multiplier = CreateByNumerator(that);
            return this.Mul(multiplier);
        }

        public RealNumber Div(int that)
        {
            int dp = this.ChunksAfterDecimalPoint;
            if (dp == 0)
            {
                dp = 1;
            }
            return Div(that, dp);
        }

        public RealNumber Div(int that, int decp)
        {
            RealNumber divider_recip = CreateByDenominator(that, decp);
            return this.Mul(divider_recip);
        }

        public double ToDouble()
        {
            if (this.mSign == Sign.Zero)
            {
                return 0;
            }

            double res = 0;
            int i;
            int j;
            for (i = this.mEffeciveLength - 1, 
                j = i - this.mDecimalPointPos; i >= 0; i--, j--)
            {
                double rate = Math.Pow(2, j*32);
                UInt32 value = this.mChunks[i];
                res += value * rate;
            }

            if (this.mSign == Sign.Negative)
            {
                res = -res;
            }

            return res;
        }

        public override string ToString()
        {
            if (this.mSign == Sign.Zero)
            {
                return "0";
            }
            StringBuilder sb = new StringBuilder();
            int i;
            if (this.mSign == Sign.Negative)
            {
                sb.Append("-");
            }
            if (this.mDecimalPointPos <= this.mEffeciveLength)
            {
                for (i = this.mEffeciveLength - 1; i >= this.mDecimalPointPos; i--)
                {
                    sb.Append(string.Format("{0:x8}", this.mChunks[i]));
                }

                if (i >= 0)
                {
                    sb.Append(".");
                    for (; i >= 0; i--)
                    {
                        sb.Append(string.Format("{0:x8}", this.mChunks[i]));
                    }
                }
            }
            else // this.mDecimalPointPos > this.mEffeciveLength
            {
                sb.Append(".");
                for (i = this.mDecimalPointPos - 1; i >= this.mEffeciveLength; i--)
                {
                    sb.Append("00000000");
                }

                for ( ; i >= 0; i++)
                {
                    sb.Append(string.Format("{0:x8}", this.mChunks[i]));
                }
            }

            return sb.ToString();
        }

        public static RealNumber operator +(RealNumber a, RealNumber b)
        {
            return a.Add(b);
        }

        public static RealNumber operator +(RealNumber a, int b)
        {
            return a.Add(b);
        }

        public static RealNumber operator +(int a, RealNumber b)
        {
            return b.Add(a);
        }

        public static RealNumber operator -(RealNumber a, RealNumber b)
        {
            return a.Sub(b);
        }

        public static RealNumber operator -(RealNumber a, int b)
        {
            return a.Sub(b);
        }

        public static RealNumber operator -(int a, RealNumber b)
        {
            RealNumber c = b.Sub(a);
            c.TurnNegative();
            return c;
        }

        public static RealNumber operator *(RealNumber a, RealNumber b)
        {
            return a.Mul(b);
        }

        public static RealNumber operator *(RealNumber a, int b)
        {
            return a.Mul(b);
        }

        public static RealNumber operator *(int a, RealNumber b)
        {
            return b.Mul(a);
        }

        public static RealNumber operator /(RealNumber a, int b)
        {
            return a.Div(b);
        }

        public static RealNumber operator -(RealNumber a)
        {
            return a.GetNegative();
        }

        public override bool Equals(object obj)
        {
            RealNumber that = obj as RealNumber;
            if (that == null)
            {
                return false;
            }
            return this.CompareTo(that) == 0;
        }

        public bool Equals(RealNumber that)
        {
            return this.CompareTo(that) == 0;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public static bool operator ==(RealNumber a, RealNumber b)
        {
            return a.CompareTo(b) == 0;
        }

        public static bool operator ==(RealNumber a, int b)
        {
            return a.CompareTo(RealNumber.CreateByNumerator(b)) == 0;
        }

        public static bool operator ==(int a, RealNumber b)
        {
            return b.CompareTo(RealNumber.CreateByNumerator(a)) == 0;
        }

        public static bool operator !=(RealNumber a, RealNumber b)
        {
            return a.CompareTo(b) != 0;
        }

        public static bool operator !=(RealNumber a, int b)
        {
            return a.CompareTo(RealNumber.CreateByNumerator(b)) != 0;
        }

        public static bool operator !=(int a, RealNumber b)
        {
            return b.CompareTo(RealNumber.CreateByNumerator(a)) != 0;
        }

        public static bool operator <(RealNumber a, RealNumber b)
        {
            return a.CompareTo(b) < 0;
        }

        public static bool operator <(RealNumber a, int b)
        {
            return a.CompareTo(RealNumber.CreateByNumerator(b)) < 0;
        }

        public static bool operator <(int a, RealNumber b)
        {
            return b.CompareTo(RealNumber.CreateByNumerator(a)) > 0;
        }

        public static bool operator >(RealNumber a, RealNumber b)
        {
            return a.CompareTo(b) > 0;
        }

        public static bool operator >(RealNumber a, int b)
        {
            return a.CompareTo(RealNumber.CreateByNumerator(b)) > 0;
        }

        public static bool operator >(int a, RealNumber b)
        {
            return b.CompareTo(RealNumber.CreateByNumerator(a)) < 0;
        }

        /*
         * internal functional modules
         */

        protected static int Compare(UInt32[] a, UInt32[] b,
            int deca, int decb, int ecla, int eclb)
        {
            int i, j;

            int inta = ecla - deca;
            int intb = eclb - decb;

            if (inta > intb)
            {
                return 1;
            }
            else if (inta < intb)
            {
                return -1;
            }

            for (i = ecla - 1, j = eclb - 1;
                i >= 0 && j >= 0; i--, j--)
            {
                if (a[i] > b[j])
                {
                    return 1;
                }
                else if (a[i] < b[j])
                {
                    return -1;
                }
            }

            for (; i >= 0; i--)
            {
                if (a[i] > 0)
                {
                    return 1;
                }
            }

            for (; j >= 0; j--)
            {
                if (b[j] > 0)
                {
                    return -1;
                }
            }

            return 0;
        }

        public static void Add(out UInt32[] result, out int decr, out int eclr,
            UInt32[] a, UInt32[] b, int deca, int decb, int ecla, int eclb)
        {
            int i, j;
            UInt32 va, vb, vt, vr;
            UInt32 c;

            UInt32[] decintro = null;
            int decintrolen = 0;
            UInt32[] follower = null;
            UInt32[] longer = null;
            int longerstart = 0;

            int inta = ecla - deca; /* might be negative */
            int intb = eclb - decb;
            int hida;
            int hidb;
            int hidmin;
            int hidmax;

            if (deca < decb)
            {
                decr = decb;
                decintro = b;
                follower = a;
                decintrolen = decb - deca;
            }
            else if (deca > decb)
            {
                decr = deca;
                decintro = a;
                follower = b;
                decintrolen = deca - decb;
            }
            else
            {
                decr = deca;
                decintro = a;
                follower = b;
            }

            hida = inta + decr;
            hidb = intb + decr;

            if (hida < hidb)
            {
                hidmin = hida;
                hidmax = hidb;
                eclr = hidb;
                if (b[eclb - 1] == kMaxU32)
                {
                    eclr++;  /* possibly take one more chunk */
                }
                longer = b;
                longerstart = eclb - (hidb - hida);
            }
            else if (hida > hidb)
            {
                hidmin = hidb;
                hidmax = hida;
                eclr = hida;
                if (a[ecla - 1] == kMaxU32)
                {
                    eclr++;  /* possibly take one more chunk */
                }
                longer = a;
                longerstart = ecla - (hida - hidb);
            }
            else
            {   /* hida == hidb */
                hidmax = hidmin = hida;
                eclr = hida;
                va = a[ecla - 1];
                vb = b[eclb - 1];
                c = 0;
                vt = va + 1;
                if (vt < va)
                {
                    c = 1;
                }
                vr = vb + vt;
                if (vr < vb)
                {
                    c = 1;
                }
                if (c == 1)
                {
                    eclr++;
                }
            }

            result = new UInt32[eclr];

            for (i = 0; i < decintrolen; i++)
            {
                result[i] = decintro[i];
            }

            c = 0;
            for (j = 0; i < hidmin; i++, j++)
            {
                va = decintro[i];
                vb = follower[j];
                vt = vb + c;
                c = 0;
                if (vt < vb)
                {
                    c = 1;
                }
                vr = va + vt;
                if (vr < va)
                {
                    c = 1;
                }
                result[i] = vr;
            }

            for (; longerstart < 0; longerstart++, i++)
            {
                result[i] = c;
                c = 0;
            }

            for (j = longerstart; i < hidmax; i++, j++)
            {
                vb = longer[j];
                vr = vb + c;
                c = 0;
                if (vr < vb)
                {
                    c = 1;
                }
                result[i] = vr;
            }

            if (c > 0)
            {
                result[i] = c;
                i++;
            }

            eclr = i;
        }

        /*
         * pre: 'a' is larger than 'b'
         */
        protected static void Sub(out UInt32[] result, out int decr, out int eclr,
            UInt32[] a, UInt32[] b, int deca, int decb, int ecla, int eclb)
        {
            UInt32 va;
            UInt32 vb;
            UInt32 vt = 0;
            UInt32 vr = 0;
            UInt32 c = 0;


            int i = 0;
            int j = 0;  // for 'a'
            int k = 0;  // for 'b'
            int d;

            if (deca < decb)
            {
                decr = decb;
                result = new UInt32[ecla + decb - deca];
                d = decb - deca;
                for (i = 0; i < d; i++)
                {
                    va = 0;
                    vb = b[i];
                    vt = vb + c;
                    c = 1;
                    vr = va - vt;
                    result[i] = vr;
                }
                k = i;
            }
            else /* deca >= decb */
            {
                decr = deca;
                result = new UInt32[ecla];
                d = deca - decb;
                for (i = 0; i < d; i++)
                {
                    va = a[i];
                    result[i] = va;
                }
                j = i;
            }

            /*
             * 'b' finishes first in this round
             * so use 'eclb' as boundary check condition
             */
            for (; k < eclb; i++, j++, k++)
            {
                va = a[j];
                vb = b[k];
                vt = vb + c;
                c = 0;
                if (vt < vb)
                {   /* vt == 0 */
                    c = 1;
                }
                vr = va - vt;
                if (vr > va)
                {
                    c = 1;
                }
                result[i] = vr;
            }

            for (; j < ecla; i++, j++)
            {
                va = a[j];
                vr = va - c;
                c = 0;
                if (vr > va)
                {
                    c = 1;
                }
                result[i] = vr;
            }

            eclr = (vr > 0) ? i : i - 1;
        }

        protected static int AddValue(ref UInt32[] res, UInt32 v, int pos16)
        {
            int pos32 = pos16 >> 1;
            int i = pos32;

            if ((pos16 & 1) == 0)
            {
                UInt32 vs = res[i];
                UInt32 vr = vs + v;
                res[i] = vr;
                i++;
                if (vr < vs)
                {
                    // carry
                    for (; i < res.Length; i++)
                    {
                        res[i]++;
                        if (res[i] > 0)
                        {
                            i++;
                            break;
                        }
                    }
                }
            }
            else
            {
                UInt32 vs = res[i];
                UInt32 vlo = v << 16;
                UInt32 vhi = v >> 16;

                UInt32 vr = vs + vlo;
                res[i] = vr;
                UInt32 c = 0;
                if (vr < vs)
                {
                    vhi++;  // add the carry to vhi
                    if (vhi == 0)
                    {
                        c = 1;  // carry for hi
                    }
                }

                i++;
                vs = res[i];

                vr = vs + vhi;
                res[i] = vr;
                i++;
                if (vr < vs)
                {
                    c = 1;
                }
                if (c == 1)
                {
                    // carry
                    for (; i < res.Length; i++)
                    {
                        res[i]++;
                        if (res[i] > 0)
                        {   // no more carry
                            i++;
                            break;
                        }
                    }
                }
            }

            return res[i - 1] > 0 ? i : i - 1;
        }

        protected static int Mul(out UInt32[] result, UInt32[] a, UInt32[] b,
            int ecla, int eclb)
        {
            int ecl = ecla + eclb;

            int ecla2 = ecla + ecla;
            int eclb2 = eclb + eclb;

            if (a[ecla - 1] < kMaxU16P1)
            {
                ecla2--;
            }
            if (b[eclb - 1] < kMaxU16P1)
            {
                eclb2--;
            }

            UInt32 va;
            UInt32 vb;
            UInt32 vr;

            result = new UInt32[ecl];
            int nHighestChunk = 0;
            int nChunkPos = 0;

            for (int i = 0; i < ecla2; i++)
            {
                for (int j = 0; j < eclb2; j++)
                {
                    int si = i >> 1;
                    int sj = j >> 1;

                    if ((i & 1) == 1)
                    {
                        va = (a[si] >> 16);
                    }
                    else
                    {
                        va = (a[si] & kMaxU16);
                    }
                    if ((j & 1) == 1)
                    {
                        vb = (b[sj] >> 16);
                    }
                    else
                    {
                        vb = (b[sj] & kMaxU16);
                    }

                    vr = va * vb;

                    nChunkPos = AddValue(ref result, vr, i + j);
                    if (nHighestChunk < nChunkPos)
                    {
                        nHighestChunk = nChunkPos;
                    }
                }
            }

            return nHighestChunk;
        }

    }
}
